using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using Unity.VisualScripting;

struct LocationInformation {
    public int x, y;
};

public class GreedySnake : MonoBehaviour {

    // Entities and their states / Model
    private static int[,] gridDirect = new int[11, 11];
    private static int[,] gridState = new int[11, 11];
    private static LocationInformation[] body = new LocationInformation[121];
    private static int bodyLength = 2;
    private static Texture2D backGroundImg;
    private static Texture2D bodyImg;
    private static Texture2D headImg;
    private static Texture2D emptyImg;
    private static Texture2D fruitImg;
    private static Texture2D bodyCrossImg;
    private static Texture2D speedEffectImg;
    private static bool isOver = false;
    private static bool isRunning = false;
    private static int curDirect = 3;
    private static int nextDirect = 3;
    private static int occupied = 0;
    private static float waitTime = 1.5f;
    private static float sumTime = 0.0f;
    private static float pressTime = 0.0f;
    private static float accelerateTime = 0.0f;
    private static float actionInterval = 0.0f;

    // System Handlers
    void Start () {
        Init();
        GenerateFruit();
    }

    // View render entities / models
    // Here! you cannot modify model directly, use components/controls to do it
    void OnGUI() {
        sumTime += Time.deltaTime;
        actionInterval += Time.deltaTime;

        // 每经过一个waitTime就移动一次蛇
        if(sumTime > waitTime) {
            if(isRunning) {
                NextMove();
                GenerateAccelerate();
            }
            sumTime -= waitTime;
        }
        
        // 背景图片
        GUI.Label(new Rect(Screen.width/2-215, Screen.height/2-215, 430, 430), backGroundImg);

        // 显示游戏画面
        GUI.Box(new Rect(Screen.width/2-215, Screen.height/2-215, 430, 430), "");
        for(int i = 0; i < 11; i++) {
            for(int j = 0; j < 11; j++) {
                switch(gridState[i, j]) {
                    case 1:
                        GUI.Label(new Rect(Screen.width/2-(5-i)*32 - 15, Screen.height/2-(5-j)*32 - 15, 30, 30), bodyImg);
                        break;
                    case 2:
                        GUI.Label(new Rect(Screen.width/2-(5-i)*32 - 15, Screen.height/2-(5-j)*32 - 15, 30, 30), headImg);
                        break;
                    case 3:
                        GUI.Label(new Rect(Screen.width/2-(5-i)*32 - 15, Screen.height/2-(5-j)*32 - 15, 30, 30), fruitImg);
                        break;
                    case 4:
                        GUI.Label(new Rect(Screen.width/2-(5-i)*32 - 15, Screen.height/2-(5-j)*32 - 15, 30, 30), bodyCrossImg);
                        break;
                    case 5:
                        GUI.Label(new Rect(Screen.width/2-(5-i)*32 - 15, Screen.height/2-(5-j)*32 - 15, 30, 30), speedEffectImg);
                        break;
                    default:
                        GUI.Label(new Rect(Screen.width/2-(5-i)*32 - 15, Screen.height/2-(5-j)*32 - 15, 30, 30), emptyImg);
                        break;
                }
            }
        }

        // 游戏结束
        if(isOver) {
            isRunning = false;
            GUI.Box(new Rect(Screen.width/2-125, Screen.height/2-30, 250, 60), $"Game Over!\nFinal Score:{bodyLength-2}\nPress SPACE To Restart");
            if(Input.GetKey(KeyCode.Space)) {
                Init();
                GenerateFruit();
            }
        } else {
            // 显示当前分数
            GUI.Box(new Rect(Screen.width/2+230, Screen.height/2-20, 50, 40), $"Score:\n{bodyLength-2}");
            if(!isRunning) {
                // 游戏暂停中
                GUI.Box(new Rect(Screen.width/2-125, Screen.height/2-20, 250, 40), "PAUSED\nPress ESC Again To Back In Game");
            }
        }

        CheckKeys();
    }

    // Components
    // here! any ui can not be referenced
    void Init() {
        isOver = false;
        isRunning = true;

        for(int i = 0; i < 11; i++)
            for(int j = 0; j < 11; j++){
                gridState[i, j] = 0;
                body[i*11 + j].x = 0;
                body[i*11 + j].y = 0;
            }

        // 加载图片资源
        if(backGroundImg == null) {
            backGroundImg = AssetDatabase.LoadAssetAtPath<Texture2D>("Assets/Images/backGround.png");
            bodyImg = AssetDatabase.LoadAssetAtPath<Texture2D>("Assets/Images/body.png");
            headImg = AssetDatabase.LoadAssetAtPath<Texture2D>("Assets/Images/head.png");
            emptyImg = AssetDatabase.LoadAssetAtPath<Texture2D>("Assets/Images/empty.png");
            fruitImg = AssetDatabase.LoadAssetAtPath<Texture2D>("Assets/Images/fruit.png");
            bodyCrossImg = AssetDatabase.LoadAssetAtPath<Texture2D>("Assets/Images/bodyCross.png");
            speedEffectImg = AssetDatabase.LoadAssetAtPath<Texture2D>("Assets/Images/speedUp.png");
        }

        // 生成初始的蛇
        int startX = Random.Range(1, 10);
        int startY = Random.Range(1, 10);
        curDirect = Random.Range(1, 4);
        bodyLength = 2;
        occupied = 0;
        accelerateTime = 0;

        // 生成头部
        gridState[startX , startY] = 2;
        gridDirect[startX , startY] = curDirect;
        body[0].x = startX;
        body[0].y = startY;
        
        // 生成尾部
        switch(curDirect) {
            case 1:
                gridState[startX , startY+1] = 1;
                gridDirect[startX , startY+1] = curDirect;
                body[1].x = startX;
                body[1].y = startY+1;
                break;
            case 2:
                gridState[startX-1 , startY] = 1;
                gridDirect[startX-1 , startY] = curDirect;
                body[1].x = startX-1;
                body[1].y = startY;
                break;
            case 3:
                gridState[startX , startY-1] = 1;
                gridDirect[startX , startY-1] = curDirect;
                body[1].x = startX;
                body[1].y = startY-1;
                break;
            default:
                gridState[startX+1 , startY] = 1;
                gridDirect[startX+1 , startY] = curDirect;
                body[1].x = startX+1;
                body[1].y = startY;
                break;
        }
    }

    // 检测键盘输入
    void CheckKeys() {
        // 检测键盘输入
        bool isPressed = false;
        if(Input.GetKey(KeyCode.UpArrow) || Input.GetKey(KeyCode.W)) {
            // 按下向上的方向键
            isPressed = true;
            if(curDirect == 1) {
                pressTime += Time.deltaTime;
            } else {
                pressTime = 0;
            }
            if(curDirect != 3)
                nextDirect = 1;
        }
        if(Input.GetKey(KeyCode.RightArrow) || Input.GetKey(KeyCode.D)) {
            // 按下向右的方向键
            isPressed = true;
            if(curDirect == 2) {
                pressTime += Time.deltaTime;
            } else {
                pressTime = 0;
            }
            if(curDirect != 4)
                nextDirect = 2;
        }
        if(Input.GetKey(KeyCode.DownArrow) || Input.GetKey(KeyCode.S)) {
            // 按下向下的方向键
            isPressed = true;
            if(curDirect == 3) {
                pressTime += Time.deltaTime;
            } else {
                pressTime = 0;
            }
            if(curDirect != 1)
                nextDirect = 3;
        }
        if(Input.GetKey(KeyCode.LeftArrow) || Input.GetKey(KeyCode.A)) {
            // 按下向左的方向键
            isPressed = true;
            if(curDirect == 4) {
                pressTime += Time.deltaTime;
            } else {
                pressTime = 0;
            }
            if(curDirect != 2)
                nextDirect = 4;
        }
        if(Input.GetKey(KeyCode.Escape)) {
            if(actionInterval > 0.5f) {
                if(!isRunning) {
                    isRunning = true;
                    actionInterval = 0;
                }
                else {
                    isRunning = false;
                    actionInterval = 0;
                }
            }
        }
        if(isRunning) {
            waitTime = 1.5f;
            if(!isPressed)
                pressTime = 0;
            if(pressTime > 0.5f)
                waitTime = 0.8f;
            if(pressTime > 2.5f)
                waitTime = 0.5f;
            if(accelerateTime > 0) {
                accelerateTime -= Time.deltaTime;
                // 加至2倍速
                waitTime /= 2;
            }
        }
    }

    // 将蛇移动一步
    void NextMove() {
        int spawnX, spawnY;
        bool doSpawn = false;

        curDirect = nextDirect;
        gridDirect[body[0].x , body[0].y] = curDirect;
        // 先移动蛇的头
        switch (curDirect)
        {
            case 1:
                body[0].y--;
                break;
            case 2:
                body[0].x++;
                break;
            case 3:
                body[0].y++;
                break;
            default:
                body[0].x--;
                break;
        }
        if(body[0].x<0 || body[0].x>10 || body[0].y<0 || body[0].y>10) {
            // 撞到边界
            isOver = true;
            return;
        }
            
        if(gridState[body[0].x , body[0].y]==1 && (body[bodyLength-1].x != body[0].x || body[bodyLength-1].y != body[0].y)) {
            // 撞到身体
            gridState[body[0].x , body[0].y] = 4;
            isOver = true;
            return;
        }

        if(gridState[body[0].x , body[0].y] == 3) {
            // 吃到果子，在所有身体移动完后再在尾部添加新的身体
            doSpawn = true;
        }

        if(gridState[body[0].x , body[0].y] == 5) {
            // 加速
            accelerateTime = 3.0f;
            occupied--;
        }

        // 记录最后一节身体的所在位置
        spawnX = body[bodyLength-1].x;
        spawnY = body[bodyLength-1].y;

        // 移动身体
        for(int i = 1; i < bodyLength; i++){
            switch (gridDirect[body[i].x , body[i].y])
            {
                case 1:
                    body[i].y--;
                    break;
                case 2:
                    body[i].x++;
                    break;
                case 3:
                    body[i].y++;
                    break;
                default:
                    body[i].x--;
                    break;
            }
            gridState[body[i].x , body[i].y] = 1;
        }

        if(doSpawn) {
            // 吃到果子，在尾部添加新的身体，并生成新的果子
            body[bodyLength].x = spawnX;
            body[bodyLength].y = spawnY;
            bodyLength++;
            GenerateFruit();
        } else {
            // 否则将最后一节身体旧位置的状态复原
            gridState[spawnX , spawnY] = 0;
        }

        gridDirect[body[0].x , body[0].y] = curDirect;
        gridState[body[0].x , body[0].y] = 2;
        
    }

    // 生成一个果子
    void GenerateFruit() {
        if(bodyLength + occupied == 121)
            return;
        int spawnX = 0, spawnY = 0;
        int spawnPos = Random.Range(1, 121-bodyLength-occupied), addEmpty = 0;
        for(int i = 0; i < 11; i++) {
            for(int j = 0; j < 11; j++) {
                if(gridState[i, j] == 0) {
                    addEmpty++;
                    if(addEmpty == spawnPos) {
                        spawnX = i;
                        spawnY = j;
                        break;
                    }
                }
            }
        }
        gridState[spawnX , spawnY] = 3;
    }

    // 生成加速块
    void GenerateAccelerate() {
        if(bodyLength + occupied == 121)
            return;
        int spawnPos, spawnX = 0, spawnY = 0, addEmpty = 0;
        if(occupied<5 && Random.Range(1, 15)==1) {
            // 概率生成加速块
            spawnPos = Random.Range(1, 121-bodyLength-occupied);
            for(int i = 0; i < 11; i++) {
                for(int j = 0; j < 11; j++) {
                    if(gridState[i, j] == 0) {
                        addEmpty++;
                        if(addEmpty == spawnPos) {
                            spawnX = i;
                            spawnY = j;
                            break;
                        }
                    }
                }
            }
            gridState[spawnX , spawnY] = 5;
            occupied++;
        }
    }
}
